#include <Precomp.h>
#include <GameWorld.h>
#include <Player.h>
#include <GameShipExplosionManager.h>

using namespace Ogre;

class CShipExplosion 
{
public:
    CShipExplosion(Ogre::BillboardSet* pBillboardSetExplosion, CGamePlayer* pPlayer, CGameWorld* pGameWorld) : m_pBillboardSetExplosion(pBillboardSetExplosion), m_pGameWorld(pGameWorld), m_flTotalTime(0.0f), m_idxCurrent(0)
    {
        m_pExplosionBillboard = pBillboardSetExplosion->createBillboard(1.0f * pPlayer->GetRenderedXLocation(), 1.0f * pPlayer->GetRenderedYLocation(), 0.0f);
        m_pExplosionBillboard->setTexcoordIndex(m_idxCurrent);

        m_pEventSubscription = pGameWorld->SubscribeEvents( CGameWorld::EventSubscriber(&CShipExplosion::OnGameWorldEvent, this));
    }

    void OnGameWorldEvent(CGameWorldEvent* pGameWorldEvent)
    {
        if(pGameWorldEvent->GetEventID() != eGameWorldEventID_BeginFrameUpdate)
        {
            return;
        }

        m_flTotalTime += m_pGameWorld->GetTimeSinceLastFrameAsFloat();

       if(m_flTotalTime > (1.0f / 15.0f))
       {
           m_flTotalTime -= (1.0f / 15.0f);
           m_idxCurrent++;
           if(m_idxCurrent >= 8)
           {
               m_idxCurrent = 0;
           }

           m_pExplosionBillboard->setTexcoordIndex(m_idxCurrent);
       }
        
    }

    ~CShipExplosion()
    {
        m_pGameWorld->UnsubscribeEvents(m_pEventSubscription);
    }
private:
    Ogre::BillboardSet* m_pBillboardSetExplosion;
    Ogre::Billboard* m_pExplosionBillboard;
    CGameWorld::CEventSubscription* m_pEventSubscription;
    CGameWorld* m_pGameWorld;
    float m_flTotalTime;
    unsigned short m_idxCurrent;
};


CGameShipExplosionManager::CGameShipExplosionManager(CGameWorld* pGameWorld) : m_pGameWorld(pGameWorld), m_flUpdateTime(0.0f)
{
    m_pEventSubscription = m_pGameWorld->SubscribeEvents( CGameWorld::EventSubscriber(&CGameShipExplosionManager::OnGameWorldEvent, this));

    m_pBillboardSetExplosion = m_pGameWorld->GetSceneManager()->createBillboardSet("Explosion", 12);
    m_pBillboardSetExplosion->setCullIndividually(true);
    m_pBillboardSetExplosion->setMaterialName("explosionMaterial");
    m_pBillboardSetExplosion->setDefaultDimensions(1500.0f, 1500.0f);
    m_pBillboardSetExplosion->setTextureStacksAndSlices(4, 4);
    m_pBillboardSetExplosion->setBillboardRotationType(BBR_VERTEX);
    m_pBillboardSetExplosion->setBounds(AxisAlignedBox(-10000000.0f, -10000000.0f, -10000000.0f, 10000000.0f, 10000000.0f, 10000000.0f), 
                                   1000000.0f);

    m_pNode = m_pGameWorld->GetSceneManager()->createSceneNode("Explosion");
    m_pNode->attachObject(m_pBillboardSetExplosion);

    m_pGameWorld->GetSceneManager()->getRootSceneNode()->addChild(m_pNode);
}

CGameShipExplosionManager::~CGameShipExplosionManager()
{
    m_pGameWorld->UnsubscribeEvents(m_pEventSubscription);

    if(m_pBillboardSetExplosion != NULL)
    {
        m_pNode->detachObject(m_pBillboardSetExplosion);
        m_pNode->getCreator()->destroyBillboardSet(m_pBillboardSetExplosion);
        m_pBillboardSetExplosion = NULL;
    }

    if(m_pNode != NULL)
    {
        if(m_pNode->getParentSceneNode() != NULL)
        {
            m_pNode->getParentSceneNode()->removeChild(m_pNode);

        }
        m_pNode->getCreator()->destroySceneNode(m_pNode->getName());
        m_pNode = NULL;
    }
}

void CGameShipExplosionManager::Update()
{
    m_flUpdateTime += m_pGameWorld->GetTimeSinceLastFrameAsFloat();
    if(m_flUpdateTime > 1.0f / 30.0f)
    {
        m_flUpdateTime = 0.0f;

        for(int idx = 0; idx < (int)m_explosions.size(); idx++)
        {
            ShipExplosion& shipExplosion = m_explosions[idx];

            if(!shipExplosion.m_isReversed)
            {
                shipExplosion.m_idxCurrent++;

                if(shipExplosion.m_idxCurrent >= 8)
                {
                    shipExplosion.m_idxCurrent = 7;
                    shipExplosion.m_isReversed = true;
                }

                if(shipExplosion.m_idxCurrent >= 0)
                {                         
                    shipExplosion.m_pBillboard->setTexcoordIndex((unsigned short) shipExplosion.m_idxCurrent);
                }
            }
            else
            {
                shipExplosion.m_idxCurrent--;

                if(shipExplosion.m_idxCurrent < 0)
                {
                    m_pBillboardSetExplosion->removeBillboard(shipExplosion.m_pBillboard);
                    m_explosions.erase(m_explosions.begin() + idx);
                    idx--;
                }
                else
                {
                    shipExplosion.m_pBillboard->setTexcoordIndex((unsigned short) shipExplosion.m_idxCurrent);
                }
            }
        }
    }

}

void CGameShipExplosionManager::AddExplosion(float rotation, float xPosition, float yPosition, int initialIndex)
{
    ShipExplosion shipExplosion;

    shipExplosion.m_pBillboard = m_pBillboardSetExplosion->createBillboard(xPosition, yPosition, 0.0f);
    shipExplosion.m_idxCurrent = initialIndex;
    shipExplosion.m_pBillboard->setRotation(Radian(rotation));
    shipExplosion.m_isReversed = false;

    m_explosions.push_back(shipExplosion);
}


void CGameShipExplosionManager::OnGameWorldEvent(CGameWorldEvent* pEvent)
{
    if(pEvent->GetEventID() == eGameWorldEventID_PlayerExplodes)
    {
        CGamePlayer* pPlayer = ((CPlayerEvent*)pEvent)->GetPlayer();

        for(unsigned int idx = 0; idx < 6; idx++)
        {
            AddExplosion(3.14f * 2.0f * Math::UnitRandom(),
                         1.0f * pPlayer->GetRenderedXLocation() + (Math::UnitRandom() * 500.0f) - 250.0f, 
                         1.0f * pPlayer->GetRenderedYLocation() + (Math::UnitRandom() * 500.0f) - 250.0f, -(int) (Math::UnitRandom() * 12.0f));
        }
    }
}
